{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# numpy基础"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "numpy是第三方库，不是python自带的，如果使用的是python官方发行的python，是没有numpy这个库的，需要自己安装。Numpy是Python大多数科学计算库的基础，应用十分广泛。\n",
    "windows下安装很麻烦，需要安装vs2015，或者使用https://www.lfd.uci.edu/~gohlke/pythonlibs/ 这里提供的编译好的安装包进行安装。  \n",
    "linux/OSX下保证有gcc和g++即可。  \n",
    "所以推荐安装anaconda，已经集成了numpy。  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python 中导入外部包的语法是：\n",
    "`import package as alias`\n",
    "package为包名，alias为别名，可以不写`as alias`来不取别名\n",
    "\n",
    "如果是从包里导入一个子模块的话：\n",
    "`from package import sub_module`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 导入numpy，简写为np\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "numpy主要提供的是矩阵运算的功能，底层是c语言编写的，而且用了很多优化的策略，所以性能很强"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 创建矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建一个一维向量\n",
    "v = np.array([1, 2, 3, 4])\n",
    "print(v)\n",
    "print('type:', type(v))\n",
    "print(\"v的维度:\", v.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以看到维度为(4, )，v.shape是一个tuple，(4, )表示这是一个长度为4的一维向量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建一个二维矩阵\n",
    "m = np.array([[1, 2],\n",
    "              [3, 4]])\n",
    "print(m)\n",
    "print(type(m))\n",
    "print(m.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以看到m的维度是(2,2)，也就是一个$2 \\times 2$的矩阵"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "m2 = np.array([[1], \n",
    "               [2],\n",
    "               [3],\n",
    "               [4]])\n",
    "print(m2.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以看到，m2的维度是(4, 1)，说明这是一个4行1列的矩阵，而v的维度是(4, )，说明v是一个长度为4的一维向量，注意两者的区别。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#将m2变成一个1行4列的矩阵\n",
    "m3 = m2.reshape(1, 4) \n",
    "print(m3)\n",
    "print(m3.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用reshape可以对array的维度进行变换，会返回一个新的array，不会影响该array原来的维度"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在二维的array中，reshape只要指定一个维度即可，另一个维度可以设置为-1，让它自动计算。比如，我们已经知道了m3是一个1行4列的矩阵，我们想将其变成一个1列的矩阵，有多少行让它自己计算，那么就使用reshape(-1, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "m3.reshape(-1, 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 取元素"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在机器学习任务中，我们一般把行作为样本，也就是一行表示一个样本，列作为特征，也就是一列表示一个特征。假设我们有数据集data，data是一个4行3列的数据集。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = np.random.uniform(0, 1, size = (4, 3))\n",
    "print(data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们想取出第2行第2列的值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 取第二行第二列\n",
    "data[1, 1] # 下标从0开始"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里使用切片的方法，这个切片和python的list的切片类似，忘了的可以回前面看一下。  \n",
    "切片中的第一个数字表示多少行，第二个数字表示多少列，下标从0开始，所以第二行第二列的值即为data[2, 2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 取第二行，第三列\n",
    "data[1, 2]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在机器学习任务中，我们经常会取一个样本，或取一个特征，也就是在矩阵中，取一行或一列"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 取出第一行\n",
    "row_0 = data[0, :]\n",
    "print(row_0)\n",
    "print(row_0.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用切片的方法，切片中，第一个元素，0表示第一行，冒号\":\"表示从第一个元素取到最后一个元素，这样就能把第0行，所有列的元素都取到。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 取出第一行\n",
    "row_0 = data[0, 0: 3]\n",
    "print(row_0)\n",
    "print(row_0.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面这种方法和前面只用冒号得到的值一样"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 取第一列\n",
    "col_0 = data[:, 0]\n",
    "print(col_0)\n",
    "print(col_0.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以看到，不论是取行，还是取列，如果只取一行或一列，得到的值就会变成一个一维的array。很多时候我们还想让他继续保持原来的维度，这时候就需要reshape一下"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 取第一行，但还要保持二维\n",
    "row_0_ = data[0, :].reshape(1, -1)\n",
    "print(row_0_)\n",
    "print(row_0_.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 取第一列，但还要保持二维\n",
    "col_0_ = data[0, :].reshape(-1, 1)\n",
    "print(col_0_)\n",
    "print(col_0_.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 矩阵运算"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 加减法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.array([1,2])\n",
    "b = np.array([3,4])\n",
    "print(a, b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "a和b都是一个长度为2的一维向量，可以直接相加减"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a + b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a - b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "b - a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c = np.array([[1, 2], [3, 4]])\n",
    "d = np.array([[1, 1], [1, 1]])\n",
    "print('c:', c)\n",
    "print('-'*30)\n",
    "print('d:', d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "c和d是同维度的二维矩阵，也是可以直接相加减"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c + d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c - d"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 数乘"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = np.array([[1, 2, 3], [4, 5, 6]])\n",
    "print(A)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "3 * A"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "同理，还有数加"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "3 + A"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 矩阵乘法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们知道，矩阵$A \\in \\mathbb{R}^{m \\times n}$和矩阵$B \\in \\mathbb{R}^{n \\times o}$是可以直接相乘的，因为前一个矩阵的列数等于后一个矩阵的行数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = np.array([[1, 2, 3], [4, 5, 6]])\n",
    "print(A)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "B = np.array([[1, 2],\n",
    "              [3, 4],\n",
    "              [5, 6]])\n",
    "print(B)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.dot(A, B)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用np.dot完成矩阵乘法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "同理，我们将矩阵$A$转置的话，就会变成一个3行2列的矩阵，将$B$转置，变成2行3列，这两个矩阵也是可以相乘的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A.T # A的转置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "B.T # B的转置"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.dot(A.T, B.T)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 对应元素相乘"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "很多时候我们需要一种对应元素相乘的方法，$A \\in \\mathbb{R}^{m \\times n}$，$B \\in \\mathbb{R}^{m \\times n}$，定义一种乘法$\\odot$，\n",
    "$$[A \\odot B]_{ij} = [A]_{ij} * [B]_{ij} $$\n",
    "这种乘法得到的积称为哈达玛积(Hadamard product)，也称为element-wise product，通俗来说就是两个维度相同的矩阵，他们的对应元素相乘"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = np.array([[1, 2, 3], [4, 5, 6]])\n",
    "print(A)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "B = np.array([[1, 2, 3], [1, 2, 3]])\n",
    "print(B)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A * B"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用$\\ast$直接将两个array相乘，即为两个矩阵的hadamard product"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 其他方法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "很多时候我们想求一个矩阵内所有元素之和"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = np.array([[1, 2, 3], [4, 5, 6]])\n",
    "print(A)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A.sum()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.sum(A)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "很多时候我们想求一个矩阵每行的和"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A.sum(axis = 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.sum(A, axis = 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "求每列之和"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A.sum(axis = 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.sum(A, axis = 0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "求矩阵中最大的元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A.max()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "每行的最大元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A.max(axis = 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "每列的最大元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A.max(axis = 0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# test1 其他操作\n",
    "求最小值就用min，求均值就用mean，求标准差就用std，对矩阵做指数运算就用np.exp，对数就用np.log, np.log2, np.log10  \n",
    "请你求出矩阵A的最小值，均值，标准差  \n",
    "每行的最小值，每列的最小值  \n",
    "每行的均值，每列的均值  \n",
    "每行的标准差，每列的标准差  \n",
    "看一看np.exp(A)和np.log(A)的效果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# YOUR CODE HERE\n",
    "\n",
    "np.min(A)\n",
    "np.mean(A)\n",
    "np.std(A)\n",
    "\n",
    "np.min(A, axis=1)\n",
    "np.min(A, axis=0)\n",
    "\n",
    "np.mean(A, axis=1)\n",
    "np.mean(A, axis=0)\n",
    "\n",
    "np.std(A, axis=1)\n",
    "np.std(A, axis=0)\n",
    "\n",
    "np.exp(A)\n",
    "np.log(A)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "除此以外，np.exp，np.log，np.log2，np.log10等操作是可以对python中的int和float类型做运算的"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(np.exp(1))\n",
    "print(np.exp(2))\n",
    "print(np.log2(2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 取出一个一维向量中最大值的下标"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这是一个非常重要的操作，为什么这么说呢，在机器学习中，很多问题都是分类问题，也就是给你一张图片，上面有个数字，问你这个数字是几？很多算法会输出这个模型认为这个数字是0, 1, ..., 9的概率，也就是一个长度为10的一维向量。这时候我们要取出概率最大的那个数所在的下标，这个下标就代表这个数字是几了。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "比如，我们得到模型当前的输出了，输出为output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "output = np.array([ 0.33847987,  0.7492099 ,  0.20938843,  0.53851897,  0.638118  ,\n",
    "        0.52182376,  0.98172993,  0.12160851,  0.5551554 ,  0.86638236])\n",
    "output"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "可以看到，10个数，分别表示模型认为这个数字是0, 1, ..., 9的概率，我们要找数最大的那个的下标是几"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.argmax(output)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用np.argmax即可获取到最大值的下标，也就是0.9817对应的下标"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# test2 找最小值对应的下标\n",
    "使用np.argmin找出output最小值的下标"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# YOUR CODE HERE\n",
    "\n",
    "print(np.argmin(output))\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "同样的到里，argmax和argmin也支持axis这个参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = np.array([[ 0.33847987,  0.7492099 ],\n",
    "       [ 0.20938843,  0.53851897],\n",
    "       [ 0.638118  ,  0.52182376],\n",
    "       [ 0.98172993,  0.12160851],\n",
    "       [ 0.5551554 ,  0.86638236]])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "求这个矩阵，每行最大值对应的下标"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.argmax(A, axis = 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# test3 求这个矩阵，每列最小值对应的下标"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# YOUR CODE HERE\n",
    "np.argmin(A, axis=0)\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 广播（broadcast）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这是基础部分的最后一个概念，什么是广播呢，可以理解为复制，假设有两个矩阵$A \\in \\mathbb{R}^{1 \\times 3}$，$B \\in \\mathbb{R}^{3 \\times 3}$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = np.array([[1, 2, 3]])\n",
    "print(A.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "B = np.random.uniform(size = (3, 3))\n",
    "print(B.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "B"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在数学领域中，A+B是不能做的，因为两个矩阵的维度不一致，在numpy中，有一种机制叫做广播，让这两个维度不同的矩阵可以进行加减乘"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A + B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A - B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "B - A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A * B"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "仔细观察上面的四种例子，你会发现这样一个特点，在每次操作的时候，numpy将矩阵A复制了两份，变成了一个3行3列的矩阵，每行都是之前A的那一行，3行的值一样。然后再与B做操作，这样就得到了四种操作的值。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# test4那么如果A是一个3行1列的矩阵，能和B做这四种操作吗？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = np.array([[1],\n",
    "              [2],\n",
    "              [3]])\n",
    "print(A.shape)\n",
    "\n",
    "# YOUR CODE HERE\n",
    "\n",
    "A + B\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "广播的具体原理就是，如果两个矩阵都是二维的，那么只要有一个维度两个矩阵的值相等，那就会自动扩充另一维度，如果扩充，通过复制的方法，将当前的数据，沿着那个待扩充的维度不断的复制。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以上就是numpy的基础操作，最后有一个综合题"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# test5 综合练习题\n",
    "完成一个很简单的机器学习预测任务！\n",
    "我们现在有一个特别简单的模型，它是\n",
    "$$ \\hat{y} = \\frac{1}{1 + \\exp^{-xw + b}}$$\n",
    "我们现在有一个样本x，它有10个特征，这样的话它就是一个长度为10的一维向量。  \n",
    "在机器学习任务中，模型是对单个样本进行计算的，也就是说，我们有10个特征，那么参数W，有10个数，b有一个数。这样W乘以样本x，就是一个长度为10的向量，与另一个长度为10的向量进行乘积，得到一个长度为1的数，然后加上b，得到长度为1的这个数。在这个模型中，还需要对它取相反数，然后做指数运算，加1，取倒数，就得到了$\\hat{y}$，请你求出$\\hat{y}$是多少"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = np.array([ 0.78803502,  0.85090948,  0.17827904,  0.26081458,  0.61807529,\n",
    "        0.06409987,  0.70153396,  0.10446683,  0.52234655,  0.80166488])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "W = np.array([[ 0.02256906],\n",
    "       [ 0.77558206],\n",
    "       [ 0.29299293],\n",
    "       [ 0.18633   ],\n",
    "       [ 0.11959697],\n",
    "       [ 0.20485966],\n",
    "       [ 0.55220315],\n",
    "       [ 0.1510716 ],\n",
    "       [ 0.66596428],\n",
    "       [ 0.29461207]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "b = 0.39147861519281024"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你的任务是求出$\\hat{y}$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# YOUR CODE HERE\n",
    "\n",
    "1/(np.exp(-np.sum(x*W.reshape(-1))+b)+1)\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "答案是0.81173994"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "但是在实际问题中，我们往往有上千个样本，X是我们的输入，是一个1000行，10列的矩阵，表示我们有1000个样本，10个特征，那么如何使用这个模型，对这1000个样本，求出他们的1000个值呢？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. 使用for循环，将刚才对单个样本做预测的方法调用1000次即可\n",
    "    这种方法理论上没有问题，但是在python中，for循环的速度要比c和java的for慢很多，计算的时间会很长\n",
    "2. 直接使用矩阵进行运算\n",
    "    $X \\in \\mathbb{R}^{1000 \\times 10}$，$W \\in \\mathbb{R}^{10 \\times 1}$\n",
    "    $$X \\times W \\in \\mathbb{R}^{1000 \\times 1}$$\n",
    "    可以看到，矩阵X乘以矩阵W得到一个1000×1的矩阵，这恰好就是将W，分别与矩阵X的每一行相乘，得到了1000个数，然后我们直接加上b，这样利用numpy的广播机制，b就会复制999次，将b与每一行相加，得到的还是这1000个值，然后取指数，加1，求倒数即可。所以，第二种方法中，只要将前面计算单个样本中的x换成X即可。而且速度更快\n",
    "    \n",
    "请你在下方完成这两种方法，计算出1000个输出值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from time import time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "X = np.random.uniform(size = (1000, 10))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 使用for循环的计算方法\n",
    "start_time = time()\n",
    "\n",
    "# YOUR CODE HERE\n",
    "\n",
    "[1/(np.exp(-np.sum(x*W.reshape(-1))+b)+1) for x in np.transpose(X)]\n",
    "\n",
    "\n",
    "\n",
    "end_time = time()\n",
    "print('time:', end_time - start_time)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 使用矩阵运算的计算方法\n",
    "start_time = time()\n",
    "\n",
    "# YOUR CODE HERE\n",
    "\n",
    "1/(np.exp(-np.matmul(X, W) + b) + 1)\n",
    "\n",
    "\n",
    "\n",
    "end_time = time()\n",
    "print('time:', end_time - start_time)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **这里介绍的只是Numpy强大功能的冰山一角，希望大家可以养成查阅官方文档的习惯**\n",
    "Numpy文档： https://www.numpy.org/devdocs/reference/index.html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
